//
//  MsgTable.m
//  iCan - iPhone Context-Aware Navigation
//  Carnegie Mellon University - 18-842 Distributed Systems
//
//  Created by Andrew Santell on 3/26/12.
//  Copyright (c) 2012 Andrew Santell. All rights reserved.

/* Table View to display all messages for a user */

#import "MsgTable.h"
#import "iCanAppDelegate.h"
#import "iCanViewController.h"
#import "SpinnerView.h"
#import "Message.h"
#import "MsgDetails.h"
#import <sqlite3.h>

@interface MsgTable ()

@end

@implementation MsgTable
@synthesize result, message, recipient, messageData, totalArray;
@synthesize appDelegate, spinner, messages;
@synthesize inputStream, outputStream, filePath;
@synthesize messageDB, badCookie;

- (id)initWithStyle:(UITableViewStyle)style
{
    self = [super initWithStyle:style];
    if (self) {
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    messages = [[NSMutableArray alloc] init];
    appDelegate = [[UIApplication sharedApplication] delegate];
    
    [self setupDB];
    [self checkMessages];
}

- (void)viewDidUnload
{    
    sqlite3_close(messageDB);
    [self setResult: nil];
    [self setMessage:nil];
    [self setRecipient:nil];
    [self setMessageData:nil];
    [self setTotalArray:nil];
    [self setAppDelegate:nil];
    [self setSpinner:nil];
    [self setMessages:nil];
    [self setFilePath:nil];
    [self setMessageDB:nil];
    [self setInputStream:nil];
    [self setOutputStream:nil];
    [super viewDidUnload];
}

- (void) setupDB
{
    [self copyDatabaseIfNeeded];
    
    NSString *dbPath = [self getDBPath];
    NSLog(@"Path = %@", dbPath);
    
    if (sqlite3_open([dbPath UTF8String], &messageDB) == SQLITE_OK)
    {
        NSLog(@"Database opened!");
    }

    else
    {
        NSLog(@"Error opening database!"); 
        sqlite3_close(messageDB);
    }   
}

- (void) checkMessages
{
    /* Load spinner on top of screen until receiving network result */
    spinner = [[SpinnerView alloc] init];
    [spinner loadSpinnerIntoView:self.view];
    
    /*Populate message to send to server */
    message = @"get_message";
    message = [message stringByAppendingString:@";"];
    message = [message stringByAppendingString:appDelegate.myName];
    message = [message stringByAppendingString:@";"];
    message = [message stringByAppendingString:appDelegate.myCookie];
    message = [message stringByAppendingString:@";"];
    message = [message stringByAppendingString:@"\n"];
    
    /* Disable Back button while connecting to network */
    self.navigationController.navigationBar.userInteractionEnabled = NO;
    
    /* Initiate network connection */
    [self initNetworkCommunication];
}

- (void) analyzeResult
{
    NSLog(@"result = %@", result);
    
    UIAlertView *badCookieAlert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Your session has expired.  Please login again"delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
    
    if ([result isEqualToString:@"BAD_COOKIE"])
    { 
        NSLog(@"Bad Cookie");
        badCookie = TRUE;
        [badCookieAlert show];
    }
    else if ([result isEqualToString:@"no_messages"])
    { 
        NSLog(@"No messages");
    }

    else
    {
        
        totalArray = [result componentsSeparatedByString:@";"];
    
        int arrayLength = ([totalArray count]) - 1;
        int i = 0;
        Message *msg = [[Message alloc] init];
     
        /* Store "result" from network into message objects.  Add these to the database */
        while (i < arrayLength)
        {
            NSArray *tempArray = [[totalArray objectAtIndex:i] componentsSeparatedByString:@","];
            NSLog(@"temparray = %@", tempArray);
            msg.date = [tempArray objectAtIndex:0];
            msg.sender = [tempArray objectAtIndex:1];
            msg.messageData = [tempArray objectAtIndex:2];     
            msg.key = [self addMessageToDB:msg];
            i++;
        }
    
    }
        [self createArrayFromDB];
    
        result = NULL;

        /* Reload data view */
        [self.tableView reloadData];

}

-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex   
{
    if (badCookie == TRUE)
    {
        badCookie = FALSE;
        result = NULL;
        iCanViewController *mainScreen = [self.storyboard instantiateViewControllerWithIdentifier:@"MainScreen"];
        [self presentViewController:mainScreen animated:YES completion:nil];
    }
}
    
/* Creates an array of message objects which is used to build the Table View */
- (void) createArrayFromDB
{
    //Show most recent at the top
    NSString *getSQL = [NSString stringWithFormat:@"select id, date, sender, message from messages order by date desc where user = \"%@\"", appDelegate.myName];
    const char *sql = [getSQL UTF8String];
    sqlite3_stmt *selectstmt;
    if (sqlite3_prepare_v2(messageDB, sql, -1, &selectstmt, NULL) == SQLITE_OK)
    {
        while (sqlite3_step(selectstmt) == SQLITE_ROW)
        {
            Message *msg = [[Message alloc] init];
            
            msg.key = sqlite3_column_int(selectstmt, 0);
            msg.date = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 1)];
            msg.sender = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 2)];
            msg.messageData = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 3)];
            [messages addObject:msg];
            msg = [[Message alloc] init];
        }
    }
}

/* Add a message to the database */
- (long) addMessageToDB: (Message *) msg
{
    sqlite3_stmt *addStmt = nil;
    
    NSString *insertSQL = [NSString stringWithFormat:@"insert into messages(date, sender, message, user) Values(\"%@\",\"%@\",\"%@\",\"%@\")",msg.date,msg.sender,msg.messageData,appDelegate.myName];
    const char *insert_stmt = [insertSQL UTF8String];
    
    if(addStmt == nil) 
    {
        if(sqlite3_prepare_v2(messageDB, insert_stmt, -1, &addStmt, NULL) != SQLITE_OK)
            NSAssert1(0, @"Error while creating add statement. '%s'", sqlite3_errmsg(messageDB));
    }
    
    if(sqlite3_step(addStmt) != SQLITE_DONE)
    {
        NSLog(@"addStmt failure");
    }

    sqlite3_finalize(addStmt);
    return sqlite3_last_insert_rowid(messageDB);
}

- (void) removeMessageFromDB: (Message *) msg
{
    sqlite3_stmt *delStmt = nil;
    
    NSString *removeSQL = [NSString stringWithFormat:@"delete from messages where id = \"%d\"", msg.key];
    const char *remove_stmt = [removeSQL UTF8String];
    
    if(delStmt == nil) 
    {
        if(sqlite3_prepare_v2(messageDB, remove_stmt, -1, &delStmt, NULL) != SQLITE_OK)
            NSAssert1(0, @"Error while creating del statement. '%s'", sqlite3_errmsg(messageDB));
    }
    
    if(sqlite3_step(delStmt) == SQLITE_DONE)
    {
        NSLog(@"Deleted id %ld", msg.key);
    }
    else 
    {
        NSLog(@"delStmt failure");
    }
    sqlite3_finalize(delStmt);
    
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

/* If database does not exist on iPhone, copy it to the phone from the Application package */
- (void) copyDatabaseIfNeeded 
{
    /* Reference - http://www.iphonesdkarticles.com/2008/10/sqlite-tutorial-adding-data.html */
    
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSError *error;
    NSString *dbPath = [self getDBPath];
    NSLog(@"path = %@", dbPath);
    BOOL success = [fileManager fileExistsAtPath:dbPath];
    
    if(!success) 
    {
        NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"messages.db"];
        success = [fileManager copyItemAtPath:defaultDBPath toPath:dbPath error:&error];
        
        if (!success)
            NSAssert1(0, @"Failed to create writable database file with message '%@'.", [error localizedDescription]);
    }
}

- (NSString *) getDBPath 
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
    NSString *documentsDir = [paths objectAtIndex:0];
    return [documentsDir stringByAppendingPathComponent:@"messages.db"];
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [self.messages count];

}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
	/*Setting up the table*/
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
	Message *msg = [self.messages objectAtIndex:indexPath.row];
    
    UILabel *fromLabel = (UILabel *) [cell viewWithTag:10];
    fromLabel.text = msg.sender;
    UILabel *msgLabel = (UILabel *) [cell viewWithTag:11];
    msgLabel.text = msg.messageData;

    return cell;  
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    /* Create a delete button.  When an item is deleted, it needs deleted from table view, message array, and the database */
	if (editingStyle == UITableViewCellEditingStyleDelete)
	{
		Message *msg = [self.messages objectAtIndex:indexPath.row];
        
        [self.messages removeObjectAtIndex:indexPath.row];
		[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
        
        [self removeMessageFromDB:msg];
    
    }   
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    MsgDetails *detail = [self.storyboard instantiateViewControllerWithIdentifier:@"MsgDetails"];
	Message *msg = [self.messages objectAtIndex:indexPath.row];
    detail.fromText = msg.sender;
    detail.msgText = msg.messageData;
    detail.dateText = msg.date;

    [self.navigationController pushViewController:detail animated:YES];
}

/* Initiate network connection */
- (void) initNetworkCommunication
{
    
    CFReadStreamRef readStream = NULL;
    CFWriteStreamRef writeStream = NULL;
    CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)appDelegate.nodeIP, appDelegate.nodePort, &readStream, &writeStream);
    
    inputStream = (__bridge NSInputStream *) readStream;
    outputStream = (__bridge NSOutputStream *) writeStream;
    
    [inputStream setDelegate:self];
    [outputStream setDelegate:self];
    
    /* Put input and output streams into a run loop */
    [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    
    [inputStream open];
    [outputStream open];
    
    /* Put message into a format that can be sent across the network (NSData) */
    NSData *data = [[NSData alloc] initWithData:[message dataUsingEncoding:NSASCIIStringEncoding]];
    
    /* Send message to network */
    [outputStream write:[data bytes] maxLength:[data length]];
}


- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent 
{
    /* Create error popup for failed connections */
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Could not connect to host"delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
    
    switch (streamEvent) 
    {
		case NSStreamEventOpenCompleted:
			NSLog(@"Stream opened");
			break;
            
            /* Accept return message from network */
		case NSStreamEventHasBytesAvailable:
            
            if (theStream == inputStream) 
            {
                
                uint8_t buffer[1024];
                int len;
                
                while ([inputStream hasBytesAvailable]) 
                {
                    len = [inputStream read:buffer maxLength:sizeof(buffer)];
                    if (len > 0) 
                    {
                        
                        result = [[NSString alloc] initWithBytes:buffer length:len encoding:NSASCIIStringEncoding];
                        
                        if (nil != result) 
                        {
                            NSLog(@"Response: %@", result);
                        }
                    }
                }
            }
			break;			
            
		case NSStreamEventErrorOccurred:
            
            NSLog(@"Can not connect to the host!");
            NSLog(@"Error Result (Should be NULL) = %@", result);
            [inputStream close];
            [inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [outputStream close];
            [outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [spinner removeSpinner];
            [alert show];
            self.navigationController.navigationBar.userInteractionEnabled = YES;
			break;
            
		case NSStreamEventEndEncountered:
            NSLog(@"Closing Connection");
            [inputStream close];
            [inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [outputStream close];
            [outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            self.navigationController.navigationBar.userInteractionEnabled = YES;
            [spinner removeSpinner];
            [self analyzeResult];
			break;
            
		case NSStreamEventHasSpaceAvailable:
            NSLog (@"Output Buffer is Empty");
            break;
            
        default:
			NSLog(@"Unknown event");
            NSLog(@"Error Result (Should be NULL) = %@", result);
            [inputStream close];
            [inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [outputStream close];
            [outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [spinner removeSpinner];
            self.navigationController.navigationBar.userInteractionEnabled = YES;
            [alert show];
	}
}

@end
